﻿using System;
using System.Collections;
using System.Collections.Generic;
using Framework;
using TrueSync;
using TrueSync.Physics2D;

public enum JudgementTargetEnum
{
    Owner,//直接生效自己
    Target,//直接生效对方
    Rect//框体判定
}

public enum AttackRectTypeEnum
{
    AttackRect,
    CounterAttackRect,
    CountFlySubitemRect,
    ThrowAttackRect,
    StatusRect,
}

public class JudgeEventEffector : BaseEventEffector
{
    //还有判定生效后目标播放动画,爆点子物体和判定生效音效没有实现

    //判定类型
    public JudgementTargetEnum JudgementTarget;
    public int DoEffectFrames;//生效帧数
    #region 框体判定参数
    public string HangpointID;
    public AttachToParentSyncMethodEnum SyncMethod;
    public TSVector2 leftUp, rightDown;
    public AttackRectTypeEnum AttackRectType;
    public List<int> StatusRectIDs;
    #endregion
    #region 激励参数
    public StimulateTypeEnum StimulateType;
    public FP XTranslation;
    public FP XSpeed;
    public FP YTranslation;
    #endregion
    #region 公共参数
    public FP XTranslationLengthWhenGuard;
    public FP XTranslationSpeedWhenGuard;
    public List<int> CallbackEventIDsWhenGuard;
    public List<int> CallbackEventIDsWhenEffect;
    public int HPDamage;
    public int DizzyDamage;
    public int EnergyDamage;
    public string AnimationNameWhenEffect;
    public int CollisionSubitemID;
    public string SoundNameWhenEffect;
    #endregion

    AttackRectBase mAttackRect;
    ObjHandle<LogicEntity> mOwner;

    public override void DoStart(ObjHandle<LogicEntity> owner)
    {
        if (JudgementTarget == JudgementTargetEnum.Rect)
        {
            if (mAttackRect != null)
                mAttackRect.Enabled = true;
            else
            {
                RectangleShape rectangleShape = new RectangleShape(leftUp, rightDown);
                switch (AttackRectType)
                {
                    case AttackRectTypeEnum.AttackRect:
                        mAttackRect = new AttackRect(rectangleShape, TSVector2.zero, 0, owner);
                        break;
                    case AttackRectTypeEnum.ThrowAttackRect:
                        mAttackRect = new ThrowAttackRect(rectangleShape, TSVector2.zero, 0, owner);
                        break;
                    case AttackRectTypeEnum.StatusRect:
                        mAttackRect = new StatusRect(rectangleShape, TSVector2.zero, 0, owner);
                        break;
                    case AttackRectTypeEnum.CounterAttackRect:
                        mAttackRect = new CounterAttackRect(rectangleShape, TSVector2.zero, 0, owner);
                        break;
                    case AttackRectTypeEnum.CountFlySubitemRect:
                        mAttackRect = new CounterFlySubitemRect(rectangleShape, TSVector2.zero, 0, owner);
                        break;
                }

                if (mAttackRect != null)
                {
                    mAttackRect.OnCollisionCallback += OnRectCollision;
                    LogicAnimationComponent animationComponent = owner.handle.GetLogicComponent<LogicAnimationComponent>();
                    animationComponent.AddToHangpoint(HangpointID, mAttackRect, SyncMethod);
                }
            }
        }
    }

    public override void DoEvent(ObjHandle<LogicEntity> owner, params object[] allParams)
    {
        //前两个直接命中
        if(JudgementTarget == JudgementTargetEnum.Owner)
        {
            Stimulate stimulate = GenerateHitStimulate();
            TakeEffect(FightGame.Instance.GetMyEntity(owner.handle.PlayerID).handle, stimulate);
        }
        else if(JudgementTarget == JudgementTargetEnum.Target)
        {
            Stimulate stimulate = GenerateHitStimulate();
            TakeEffect(FightGame.Instance.GetRivalEntity(owner.handle.PlayerID).handle, stimulate);
        }
    }

    public override void DoFinish(ObjHandle<LogicEntity> owner)
    {
        if (mAttackRect != null)
        {
            mAttackRect.Enabled = false;
        }
    }

    bool GenerateStimulate(ObjHandle<LogicEntity> target, List<Fixture> fixtures, out Stimulate stimulate)
    {
        stimulate = null;
        if(AttackRectType == AttackRectTypeEnum.CounterAttackRect ||//如果是反击判定
            AttackRectType == AttackRectTypeEnum.CountFlySubitemRect //如果是反飞行道具判定
            )
        {
            stimulate = new BeCounterAttackedStimulate();
            return false;
        }

        bool defenseSuccess = false;
        bool hasUpStimulate = false;
        bool hasDownStimulate = false;
        for(int i = 0; i <fixtures.Count; i++)
        {
            //判断有哪些框提碰到了
            BodyHitRect hitRect = (BodyHitRect)fixtures[i];
            if (hitRect == null)
                continue;

            if (hitRect.BodyHitRectType == BodyHitRectTypeEnum.Up)
                hasUpStimulate = true;
            else if (hitRect.BodyHitRectType == BodyHitRectTypeEnum.Down)
                hasDownStimulate = true;
        }
       
        LogicStateMachineComponent targetStateMachineComponent = target.handle.GetLogicComponent<LogicStateMachineComponent>();
        if (AttackRectType == AttackRectTypeEnum.AttackRect&&//只有攻击框才有被防御的设定
            (!hasDownStimulate &&
            (targetStateMachineComponent.CurrentState.StateName == StateEnum.StandDefense ||
            targetStateMachineComponent.CurrentState.StateName == StateEnum.StandDefenseHit))//站立防御成功
            ||
            (!hasUpStimulate &&
            (targetStateMachineComponent.CurrentState.StateName == StateEnum.CrouchDefense ||
            targetStateMachineComponent.CurrentState.StateName == StateEnum.CrouchDefenseHit))//下蹲防御成功
            )
        {
            if (StimulateType != StimulateTypeEnum.NoStimulate)
            {
                HitBackStimulate hitbackStimulate = new HitBackStimulate();
                hitbackStimulate.XMoveLength = XTranslationLengthWhenGuard;
                hitbackStimulate.XMoveSpeed = XTranslationSpeedWhenGuard;
                stimulate = hitbackStimulate;
            }
            defenseSuccess = true;
        }
        else//防御失败
        {
            stimulate = GenerateHitStimulate();
            stimulate.HasDownStimulate = hasDownStimulate;
            stimulate.HasUpStimulate = hasUpStimulate;
            defenseSuccess = false;
        }

        return defenseSuccess;
    }

    Stimulate GenerateHitStimulate()//产生直接判断和没被防御的激励
    {
        Stimulate stimulate = null;
        switch (StimulateType)
        {
            case StimulateTypeEnum.NoStimulate:
                break;
            case StimulateTypeEnum.HitBackStimulate:
                HitBackStimulate hitback = new HitBackStimulate();
                hitback.XMoveLength = XTranslation;
                hitback.XMoveSpeed = XSpeed;
                stimulate = hitback;
                break;
            case StimulateTypeEnum.FalldownStimulate:
                stimulate = new FalldownStimulate();
                break;
            case StimulateTypeEnum.BeCounterAttackStimulate:
                stimulate = new BeCounterAttackedStimulate();
                break;
            case StimulateTypeEnum.ThrowStimulate:
                stimulate = new ThrowStimulate();
                break;
            case StimulateTypeEnum.HitFloatStimulate:
                HitFloatStimulate hitfloat = new HitFloatStimulate();
                hitfloat.XMoveLength = XTranslation;
                hitfloat.XMoveSpeed = XSpeed;
                hitfloat.YHeight = YTranslation;
                stimulate = hitfloat;
                break;
            case StimulateTypeEnum.HitFlyStimulate:
                HitFlyStimulate hitfly = new HitFlyStimulate();
                hitfly.XMoveLength = XTranslation;
                hitfly.XMoveSpeed = XSpeed;
                stimulate = hitfly;
                break;
        }
        return stimulate;
    }

    void OnRectCollision(List<Fixture> collidingFixtures)
    {
        ObjHandle<LogicEntity> target = (ObjHandle<LogicEntity>)collidingFixtures[0].UserData;
        Stimulate stimulate = null;
        bool defenseSuccess = GenerateStimulate(target, collidingFixtures, out stimulate);
        if (defenseSuccess)
        {
            //被防御肯定有一个击退激励
            target.handle.GetLogicComponent<LogicStateMachineComponent>().CurrentState.OnStimulate(stimulate);
            LogicEventComponent eventComponent = mOwner.handle.GetLogicComponent<LogicEventComponent>();
            for (int i = 0; i < CallbackEventIDsWhenGuard.Count; i++)
            {
                eventComponent.CallEvent(CallbackEventIDsWhenGuard[i], stimulate);
            }
        }
        else
        {
            TakeEffect(target.handle, stimulate);
        }
    }

    void TakeEffect(LogicEntity target, Stimulate stimulate)
    {
        //无激励不往这边调用
        if (stimulate != null)
        {
            target.GetLogicComponent<LogicStateMachineComponent>().CurrentState.OnStimulate(stimulate);
        }
        LogicEventComponent eventComponent = mOwner.handle.GetLogicComponent<LogicEventComponent>();
        for (int i = 0; i < CallbackEventIDsWhenEffect.Count; i++)
        {
            eventComponent.CallEvent(CallbackEventIDsWhenEffect[i], stimulate);
        }

        LogicStatusComponent targetStatusComponent = target.GetLogicComponent<LogicStatusComponent>();
        targetStatusComponent.DoDamage(HPDamage);
        targetStatusComponent.DoDizzy(DizzyDamage);
        targetStatusComponent.UseEnergy(EnergyDamage);

        //如果是状态框上状态
        if (AttackRectType == AttackRectTypeEnum.StatusRect)
        {
            //TODO:上状态，现在没状态所以先不实现
        }
    }

    public override void OnDestroy()
    {
        if(mAttackRect != null && mOwner.IsValid)
        {
            LogicAnimationComponent animationComponent = mOwner.handle.GetLogicComponent<LogicAnimationComponent>();
            animationComponent.RemoveFromHangpoint(mAttackRect);
            mAttackRect.OnDestroy();
        }
    }

    public override void Serialize(EByte ms)
    {
        ms.WriteInt((int)JudgementTarget);
        ms.WriteInt(DoEffectFrames);
        if(JudgementTarget == JudgementTargetEnum.Rect)
        {
            ms.WriteString(HangpointID);
            ms.WriteInt((int)SyncMethod);
            ms.WriteLong(leftUp.x.RawValue); ms.WriteLong(leftUp.y.RawValue);
            ms.WriteLong(rightDown.x.RawValue); ms.WriteLong(rightDown.y.RawValue);
            ms.WriteInt((int)AttackRectType);
            ms.WriteInt(StatusRectIDs.Count);
            for(int i = 0; i < StatusRectIDs.Count; i++)
            {
                ms.WriteInt(StatusRectIDs[i]);
            }
        }

        ms.WriteInt((int)StimulateType);
        ms.WriteLong(XTranslation.RawValue);
        ms.WriteLong(XSpeed.RawValue);
        ms.WriteLong(YTranslation.RawValue);
        ms.WriteLong(XTranslationLengthWhenGuard.RawValue);
        ms.WriteLong(XTranslationSpeedWhenGuard.RawValue);
        ms.WriteInt(CallbackEventIDsWhenGuard.Count);
        for(int i = 0; i < CallbackEventIDsWhenGuard.Count; i++)
        {
            ms.WriteInt(CallbackEventIDsWhenGuard[i]);
        }
        ms.WriteInt(CallbackEventIDsWhenEffect.Count);
        for(int i = 0; i < CallbackEventIDsWhenEffect.Count; i++)
        {
            ms.WriteInt(CallbackEventIDsWhenEffect[i]);
        }
        ms.WriteInt(HPDamage);
        ms.WriteInt(DizzyDamage);
        ms.WriteInt(EnergyDamage);
        ms.WriteString(AnimationNameWhenEffect);
        ms.WriteInt(CollisionSubitemID);
        ms.WriteString(SoundNameWhenEffect);
    }

    public override void Deserialize(EByte ms)
    {
        JudgementTarget = (JudgementTargetEnum)ms.ReadInt();
        DoEffectFrames = ms.ReadInt();
        if (JudgementTarget == JudgementTargetEnum.Rect)
        {
            HangpointID = ms.ReadString();
            SyncMethod = (AttachToParentSyncMethodEnum)ms.ReadInt();
            leftUp = new TSVector2(FP.FromRaw(ms.ReadLong()), FP.FromRaw(ms.ReadLong()));
            rightDown = new TSVector2(FP.FromRaw(ms.ReadLong()), FP.FromRaw(ms.ReadLong()));
            AttackRectType = (AttackRectTypeEnum)ms.ReadInt();
            int StatusRectIDsLen = ms.ReadInt();
            StatusRectIDs = new List<int>(StatusRectIDsLen);
            for(int i = 0; i < StatusRectIDsLen; i++)
            {
                StatusRectIDs.Add(ms.ReadInt());
            }
        }

        StimulateType = (StimulateTypeEnum)ms.ReadInt();
        XTranslation = FP.FromRaw(ms.ReadLong());
        XSpeed = FP.FromRaw(ms.ReadLong());
        YTranslation = FP.FromRaw(ms.ReadLong());
        XTranslationLengthWhenGuard = FP.FromRaw(ms.ReadLong());
        XTranslationSpeedWhenGuard = FP.FromRaw(ms.ReadLong());
        int CallbackWhenGuardNum = ms.ReadInt();
        CallbackEventIDsWhenEffect = new List<int>(CallbackEventIDsWhenGuard);
        for(int i = 0; i < CallbackWhenGuardNum; i++)
        {
            CallbackEventIDsWhenEffect.Add(ms.ReadInt());
        }
        int CallbackWhenEffectNum = ms.ReadInt();
        CallbackEventIDsWhenEffect = new List<int>(CallbackEventIDsWhenEffect);
        for(int i = 0; i < CallbackWhenEffectNum; i++)
        {
            CallbackEventIDsWhenEffect.Add(ms.ReadInt());
        }
        HPDamage = ms.ReadInt();
        DizzyDamage = ms.ReadInt();
        EnergyDamage = ms.ReadInt();
        AnimationNameWhenEffect = ms.ReadString();
        CollisionSubitemID = ms.ReadInt();
        SoundNameWhenEffect = ms.ReadString();
    }
}
